package chatClient.controller;

import java.io.*;
import java.net.*;
import java.util.*;

import chat.model.*;
import chatClient.view.*;
/**  'ChatClientConnection.java'  created by: Team N3 for Swinburne Uni HET715s2/Dr. Recep Ulusoy, 2/10/2012 v0.0 (final)
*	<br>
*   A simple program that accompanies the Chat Client program, called by Main.  Its main function is to handle the data
*   communications streams between Client and Server, (at the Client end).  It also has a method to read the IP addresses of 
*   the Chat Server(s) from the config file 'IP.txt'.
*   
*	<br>
*	(NOTE:  Diagnostic feedback is visible if a Command Prompt window is opened).
*
*  CLASSES CALLED:   ArrayList, InetAddrress, Socket, ChatListener, ChatSender, FileReader, BufferedReader, createConnection,
* @author Tung Nguyen, Trung V Hoang, Rob Bernard, Justin Semmel
* @see java.util.Observable
* @since September 2012 
* @see ObserverChat, ObservableChat
**/
public class ChatClientConnection implements ObserverChatSender, ObservableChatConnection
{
	private String serverFile;
	private ArrayList <InetAddress> serverList;
	private InetAddress activeServer;
	private Socket socket = null;
	private ChatListener chatListener;
	private ChatSender chatSender;
	private boolean hasActiveConnection;
	private List <ObserverChatConnection> observerConnection;
	
	/**
	*   Constructor for Connection
	*                (set up variables, Observer and IP Address of Server)
	*/
	public ChatClientConnection()
	{
		observerConnection = new ArrayList <ObserverChatConnection>();
		observerConnection.clear();
		try
		{
//			observerList= new ArrayList <ObserverChat>();
			serverList = new ArrayList<InetAddress>();
			chatListener = new ChatListener();
			chatSender = new ChatSender();
			
			hasActiveConnection = false;
				
		}
		catch(Exception ex)
		{
			// Error-handler:  Diag to CLI display
			System.out.println("\nError when allocating memory for variables!\n");
			System.exit(1); // Exit with CLI ErrorLevel=2
		}
	}
	
	/**
	*   Read Server addresses from config Server File (IP.txt)
	*   (Tries to read the IP address(es) from the config file 'IP.txt', in IPv4 format, 2 maximum, delimiter = LF)
	*	suppose that all servers listen on the same port
	*/
	public void ReadServerFile(String theServerFile)
	{
		//  Passes filename (IP.txt)
		serverFile = theServerFile;
		try
		{
			//ref: http://www.roseindia.net/java/beginners/java-read-file-line-by-line.shtml
			// Setup reading stream
			FileReader fr = new FileReader(serverFile);
			BufferedReader br = new BufferedReader( fr);
			String line;
			
			while( (line = br.readLine()) != null)
			{
				InetAddress add = InetAddress.getByName(line);
				serverList.add(add);				
			}
			
			//close the input stream
			fr.close();
		}
		catch(Exception ex)
		{
			System.out.println("Error when reading the host file");
			System.exit(3);	// Exit with CLI ErrorLevel = 3
		}
	}
	
	/**
	*   Attempt to find working Server connection
	*   (Attempts connection to Servers in IP.txt, to find a working Server, but for Task1 only uses first IP. 
	*   Later will select working Server from list, and/or flag none functioning with a User prompt - Response area?  Errorlevel5?).
	*	ASSUMPTION:  that all servers listen on the same port (6666)	
	*/
	public boolean createConnection()
	{
		System.out.println("Creating connection");
		for(InetAddress host: serverList)
		{			
			if(connectToServer(host))
			{
				//the first server that client can connect become the active server for the client
				activeServer = host;
				return true;
			}
		}
		
		return false;
	}
	
	/**
	*   Attempt to use working Server connection
	*                (Creates connection to working Server selected, TCP port 6666.  Initiates handling Thread. 
	*/
	public void closeConnection()
	{
		try
		{
			System.out.println("\nClosing connection...");
			chatListener.setStop(true);
			
			socket.close();
			hasActiveConnection = false;
		}
		catch(IOException ioEx)
		{
			System.out.println("Unable to disconnect!");
			System.exit(1);
		}
	}		
	
	/** create a connection to a server
	 * @param host
	 * @return
	 */
	private boolean connectToServer(InetAddress host)
	{
		try
		{
			socket = new Socket(host,ApplicationConstant.SERVER_PORT);
			chatListener.createInputPipe(socket.getInputStream());
			chatSender.createOutputPipe(socket.getOutputStream());
			
			//starts the listener thread
			Thread t = new Thread(chatListener);	// Starts the Listener thread
			t.start();
			hasActiveConnection = true;
			
			//t.st();
			//Timer tm = new Timer(500,createConnection);
			return true;
		}
		catch(IOException ioEx)
		{
			//can't connect to the server
			System.out.println(" Can't connect to the server");	// Diag message to CLI display
			ioEx.printStackTrace(); // Diag message to CLI display
		}
		
		return false;
	}
	
	/** add observers to the listener so whenever a new message comes, all observers will be notified.
	 * @param observer
	 */
	public void addObserverChatListener(ObserverChatListener observer){
		chatListener.addObserverChatListener(observer);
	}
	
	/** send message to the server
	 * @see chat.model.ObserverChatSender#sendMessage(java.lang.String)
	 */
	public void sendMessage(String message){
		if (hasActiveConnection)
		{
			System.out.println("Sending message");
			chatSender.sendMessage(message);
		}
	}
		
	/**
	 * create a connection to a server
	 */
	public void connectToServer()
	{
		if (!hasActiveConnection)
		{
			hasActiveConnection = createConnection();
		}
	}
	
	/**
	*   Disconnect Procedure
	*   (Closes the Server connection socket (cleanly)). 
	*/
	public void disconnectingServer()
	{
		closeConnection();
	}
	
	/** notify observer about the connection status
	 * @see chat.model.ObservableChatConnection#notifyObserverChatConnection_ConnectionStatus(java.lang.String)
	 */
	public void notifyObserverChatConnection_ConnectionStatus(String status)
	{
		for (ObserverChatConnection connection:observerConnection)
		{
			connection.updateConnectionStatus(status);
		}
	}
	
	/**
	*   Monitor messages with Observer
	*  	(add Observers to the listener so whenever a new message comes, all the Observers will be notified.). 
	*/	
	public void addObserverChatConnection(ObserverChatConnection observer)
	{
		observerConnection.add(observer);
	}
}